package main

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/panjf2000/ants/v2"
)

func main() {
	const (
		poolSize      = 5                // 协程池容量
		taskTimeout   = 2 * time.Second  // 单个任务超时时间
		totalDeadline = 10 * time.Second // 总任务执行截止时间
		taskCount     = 10               // 总任务数量
	)

	// 创建带超时控制的 context（全局截止时间）
	globalCtx, globalCancel := context.WithTimeout(context.Background(), totalDeadline)
	defer globalCancel()

	// 初始化协程池（配置 Panic 处理器）
	pool, _ := ants.NewPool(poolSize, ants.WithPanicHandler(func(p interface{}) {
		fmt.Printf("捕获 panic: %v\n", p)
	}))
	defer pool.Release()

	var (
		wg          sync.WaitGroup
		errorChan   = make(chan error, taskCount)  // 错误收集通道
		taskResults = make(chan string, taskCount) // 结果收集通道
	)

	// 定义任务函数（模拟可能失败和超时的操作）
	task := func(taskID int) error {
		// 模拟随机耗时操作（0~3秒）
		time.Sleep(time.Duration(taskID%4) * time.Second)
		if taskID%3 == 0 { // 模拟特定任务失败
			return errors.New(fmt.Sprintf("task %d 执行失败", taskID))
		}
		return nil
	}

	// 提交任务到协程池
	for i := 0; i < taskCount; i++ {
		// 检查全局截止时间是否已到
		if globalCtx.Err() != nil {
			fmt.Println("全局截止时间已到，停止提交新任务")
			break
		}

		wg.Add(1)
		taskID := i // 创建局部变量副本

		// 为每个任务创建独立的超时 context
		taskCtx, taskCancel := context.WithTimeout(globalCtx, taskTimeout)

		// 提交任务到协程池
		err := pool.Submit(func() {
			defer wg.Done()
			defer taskCancel() // 确保释放 context 资源

			// 监听任务超时或全局取消
			select {
			case <-taskCtx.Done():
				// 任务因超时或全局取消被终止
				errorChan <- fmt.Errorf("任务 %d 超时或被取消: %v", taskID, taskCtx.Err())
				return
			default:
				// 执行实际任务
				if err := task(taskID); err != nil {
					errorChan <- err // 收集业务错误
				} else {
					taskResults <- fmt.Sprintf("任务 %d 完成", taskID) // 收集成功结果
				}
			}
		})

		// 处理任务提交失败（如协程池已关闭或队列满）
		if err != nil {
			wg.Done()
			errorChan <- fmt.Errorf("提交任务 %d 失败: %v", taskID, err)
		}
	}

	// 等待所有任务完成（或全局截止时间到）
	go func() {
		wg.Wait()
		close(errorChan)
		close(taskResults)
	}()

	// 处理结果和错误
Loop:
	for {
		select {
		case res, ok := <-taskResults:
			if !ok {
				break Loop
			}
			fmt.Println("成功结果:", res)
		case err, ok := <-errorChan:
			if !ok {
				break Loop
			}
			fmt.Println("错误信息:", err)
		case <-globalCtx.Done():
			fmt.Println("全局截止时间到达，停止等待结果")
			break Loop
		}
	}

	fmt.Println("程序执行结束")
}
